home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Half-Life Model Viewer / src / pakviewer.cpp < prev    next >
C/C++ Source or Header  |  1999-05-04  |  11KB  |  557 lines

  1. //
  2. //                 Half-Life Model Viewer (c) 1999 by Mete Ciragan
  3. //
  4. // file:           pakviewer.cpp
  5. // last modified:  May 04 1999, Mete Ciragan
  6. // copyright:      The programs and associated files contained in this
  7. //                 distribution were developed by Mete Ciragan. The programs
  8. //                 are not in the public domain, but they are freely
  9. //                 distributable without licensing fees. These programs are
  10. //                 provided without guarantee or warrantee expressed or
  11. //                 implied.
  12. //
  13. // version:        1.2
  14. //
  15. // email:          mete@swissquake.ch
  16. // web:            http://www.swissquake.ch/chumbalum-soft/
  17. //
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <mx/mx.h>
  22. #include "pakviewer.h"
  23. #include "mdlviewer.h"
  24. #include "GlWindow.h"
  25. #include "StudioModel.h"
  26. #include "ControlPanel.h"
  27. #include "FileAssociation.h"
  28.  
  29.  
  30.  
  31. int
  32. pak_ExtractFile (const char *pakFile, const char *lumpName, char *outFile)
  33. {
  34.     FILE *file = fopen (pakFile, "rb");
  35.     if (!file)
  36.         return 0;
  37.  
  38.     int ident, dirofs, dirlen;
  39.  
  40.     fread (&ident, sizeof (int), 1, file);
  41.     if (ident != (int) (('K' << 24) + ('C' << 16) + ('A' << 8) + 'P'))
  42.     {
  43.         fclose (file);
  44.         return 0;
  45.     }
  46.  
  47.     fread (&dirofs, sizeof (int), 1, file);
  48.     fread (&dirlen, sizeof (int), 1, file);
  49.  
  50.     fseek (file, dirofs, SEEK_SET);
  51.     int numLumps = dirlen / 64;
  52.  
  53.     for (int i = 0; i < numLumps; i++)
  54.     {
  55.         char name[56];
  56.         int filepos, filelen;
  57.  
  58.         fread (name, 56, 1, file);
  59.         fread (&filepos, sizeof (int), 1, file);
  60.         fread (&filelen, sizeof (int), 1, file);
  61.  
  62.         if (!mx_strcasecmp (name, lumpName))
  63.         {
  64.             FILE *out = fopen (outFile, "wb");
  65.             if (!out)
  66.             {
  67.                 fclose (file);
  68.                 return 0;
  69.             }
  70.  
  71.             fseek (file, filepos, SEEK_SET);
  72.  
  73.             while (filelen--)
  74.                 fputc (fgetc (file), out);
  75.  
  76.             fclose (out);
  77.             fclose (file);
  78.  
  79.             return 1;
  80.         }
  81.     }
  82.  
  83.     fclose (file);
  84.  
  85.     return 0;
  86. }
  87.  
  88.  
  89.  
  90. PAKViewer::PAKViewer (mxWindow *window)
  91. : mxWindow (window, 0, 0, 0, 0, "", mxWindow::Normal)
  92. {
  93.     strcpy (d_pakFile, "");
  94.     strcpy (d_currLumpName, "");
  95.  
  96.     tvPAK = new mxTreeView (this, 0, 0, 0, 0, IDC_PAKVIEWER);
  97.     pmMenu = new mxPopupMenu ();
  98.     pmMenu->add ("Load Model", 1);
  99.     pmMenu->addSeparator ();
  100.     pmMenu->add ("Load Background", 2);
  101.     pmMenu->add ("Load Ground", 3);
  102.     pmMenu->addSeparator ();
  103.     pmMenu->add ("Play Sound", 4);
  104.     pmMenu->addSeparator ();
  105.     pmMenu->add ("Extract File...", 5);
  106.     setLoadEntirePAK (true);
  107.  
  108.     setVisible (false);
  109. }
  110.  
  111.  
  112.  
  113. PAKViewer::~PAKViewer ()
  114. {
  115.     tvPAK->remove (0);
  116.     closePAKFile ();
  117. }
  118.  
  119.  
  120.  
  121. void
  122. _makeTempFileName (char *str, const char *suffix)
  123. {
  124.     strcpy (str, mx_gettemppath ());
  125.  
  126.     strcat (str, "/hltempmodel");
  127.     strcat (str, suffix);
  128. }
  129.  
  130.  
  131.  
  132. int
  133. PAKViewer::handleEvent (mxEvent *event)
  134. {
  135.     switch (event->event)
  136.     {
  137.     case mxEvent::Action:
  138.     {
  139.         switch (event->action)
  140.         {
  141.         case IDC_PAKVIEWER: // tvPAK
  142.             if (event->flags & mxEvent::RightClicked)
  143.             {
  144.                 pmMenu->setEnabled (1, strstr (d_currLumpName, ".mdl") != 0);
  145.                 pmMenu->setEnabled (2, strstr (d_currLumpName, ".tga") != 0);
  146.                 pmMenu->setEnabled (3, strstr (d_currLumpName, ".tga") != 0);
  147.                 pmMenu->setEnabled (4, strstr (d_currLumpName, ".wav") != 0);
  148.                 int ret = pmMenu->popup (tvPAK, event->x, event->y);
  149.                 switch (ret)
  150.                 {
  151.                 case 1:
  152.                     OnLoadModel ();
  153.                     break;
  154.  
  155.                 case 2:
  156.                     OnLoadTexture (0);
  157.                     break;
  158.  
  159.                 case 3:
  160.                     OnLoadTexture (1);
  161.                     break;
  162.  
  163.                 case 4:
  164.                     OnPlaySound ();
  165.                     break;
  166.  
  167.                 case 5:
  168.                     OnExtract ();
  169.                     break;
  170.                 }
  171.             }
  172.             else if (event->flags & mxEvent::DoubleClicked)
  173.             {
  174.                 OnPAKViewer ();
  175.                 char e[16];
  176.  
  177.                 strncpy (e, mx_getextension (d_currLumpName), 16);
  178.                 int mode = g_FileAssociation->getMode (&e[1]);
  179.                 if (mode == -1)
  180.                     return 1;
  181.  
  182.                 char *program = g_FileAssociation->getProgram (&e[1]);
  183.  
  184. #ifdef WIN32
  185.                 if (mode == 0)
  186.                 {
  187.                     char str[256];
  188.                     _makeTempFileName (str, e);
  189.                     if (!pak_ExtractFile (d_pakFile, d_currLumpName, str))
  190.                         mxMessageBox (this, "Error extracting from PAK file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  191.                     else
  192.                     {
  193.                         if (program)
  194.                         {
  195.                             char path[256];
  196.                             strcpy (path, program);
  197.                             strcat (path, " ");
  198.                             strcat (path, str);
  199.                             if ((int) WinExec (path, SW_SHOW) <= 32)
  200.                                 mxMessageBox (this, "Error executing specified program.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  201.                         }
  202.                     }
  203.                 }
  204.  
  205.                 // associated program
  206.                 else if (mode == 1)
  207.                 {
  208.                     char str[256];
  209.                     _makeTempFileName (str, e);
  210.                     if (!pak_ExtractFile (d_pakFile, d_currLumpName, str))
  211.                         mxMessageBox (this, "Error extracting from PAK file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  212.                     else
  213.                         if ((int) ShellExecute ((HWND) getHandle (), "open", str, 0, 0, SW_SHOW) <= 32)
  214.                             mxMessageBox (this, "Error executing document with associated program.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  215.                 }
  216.  
  217.                 // HLMV default
  218.                 else    
  219. #endif
  220.                 if (mode == 2)
  221.                 {
  222.                     if (!strcmp (e, ".mdl"))
  223.                         OnLoadModel ();
  224.  
  225.                     else if (!strcmp (e, ".tga"))
  226.                         OnLoadTexture (0);
  227.  
  228.                     else if (!strcmp (e, ".wav"))
  229.                         OnPlaySound ();
  230.  
  231.                     return 1;
  232.                 }
  233.             }
  234.             
  235.             return OnPAKViewer ();
  236.         } // event->action
  237.     } // mxEvent::Action
  238.     break;
  239.  
  240.     case mxEvent::Size:
  241.     {
  242.         tvPAK->setBounds (0, 0, event->width, event->height);
  243.     } // mxEvent::Size
  244.     break;
  245.  
  246.     } // event->event
  247.  
  248.     return 1;
  249. }
  250.  
  251.  
  252.  
  253. int
  254. PAKViewer::OnPAKViewer ()
  255. {
  256.     mxTreeViewItem *tvi = tvPAK->getSelectedItem ();
  257.     if (tvi)
  258.     {
  259.         strcpy (d_currLumpName, tvPAK->getLabel (tvi));
  260.  
  261.         // find the full lump name
  262.         mxTreeViewItem *tviParent = tvPAK->getParent (tvi);
  263.         char tmp[128];
  264.         while (tviParent)
  265.         {
  266.             strcpy (tmp, d_currLumpName);
  267.             strcpy (d_currLumpName, tvPAK->getLabel (tviParent));
  268.             strcat (d_currLumpName, "/");
  269.             strcat (d_currLumpName, tmp);
  270.             tviParent = tvPAK->getParent (tviParent);
  271.         }
  272.  
  273.         if (!d_loadEntirePAK)
  274.         {
  275.             // finally insert "models/"
  276.             strcpy (tmp, d_currLumpName);
  277.             strcpy (d_currLumpName, "models/");
  278.             strcat (d_currLumpName, tmp);
  279.         }
  280.     }
  281.  
  282.     return 1;
  283. }
  284.  
  285.  
  286.  
  287. int
  288. PAKViewer::OnLoadModel ()
  289. {
  290.     static char str2[256];
  291.     char suffix[16];
  292.  
  293.     strcpy (suffix, ".mdl");
  294.     _makeTempFileName (str2, suffix);
  295.  
  296.     if (!pak_ExtractFile (d_pakFile, d_currLumpName, str2))
  297.     {
  298.         mxMessageBox (this, "Error extracting from PAK file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  299.         return 1;
  300.     }
  301.  
  302.     g_studioModel.FreeModel ();
  303.     studiohdr_t *hdr = g_studioModel.LoadModel (str2);
  304.     if (!hdr)
  305.     {
  306.         mxMessageBox (this, "Error reading model header.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  307.         return 1;
  308.     }
  309.  
  310.     if (hdr->numtextures == 0)
  311.     {
  312.         char texturename[256];
  313.  
  314.         strcpy( texturename, d_currLumpName );
  315.         strcpy( &texturename[strlen(texturename) - 4], "T.mdl" );
  316.  
  317.         strcpy (suffix, "T.mdl");
  318.         _makeTempFileName (str2, suffix);
  319.  
  320.         if (!pak_ExtractFile (d_pakFile, texturename, str2))
  321.         {
  322.             g_studioModel.FreeModel ();
  323.             mxMessageBox (this, "Error extracting from PAK file 1.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  324.             return 1;
  325.         }
  326.     }
  327.  
  328.     if (hdr->numseqgroups > 1)
  329.     {
  330.         for (int i = 1; i < hdr->numseqgroups; i++)
  331.         {
  332.             char seqgroupname[256];
  333.  
  334.             strcpy( seqgroupname, d_currLumpName );
  335.             sprintf( &seqgroupname[strlen(seqgroupname) - 4], "%02d.mdl", i );
  336.  
  337.             sprintf (suffix, "%02d.mdl", i);
  338.             _makeTempFileName (str2, suffix);
  339.  
  340.             if (!pak_ExtractFile (d_pakFile, seqgroupname, str2))
  341.             {
  342.                 g_studioModel.FreeModel ();
  343.                 mxMessageBox (this, "Error extracting from PAK file 2.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  344.                 return 1;
  345.             }
  346.         }
  347.     }
  348.  
  349.     g_studioModel.FreeModel ();
  350.  
  351.     strcpy (suffix, ".mdl");
  352.     _makeTempFileName (str2, suffix);
  353.     g_ControlPanel->loadModel (str2);
  354.  
  355.     return 1;
  356. }
  357.  
  358.  
  359.  
  360. int
  361. PAKViewer::OnLoadTexture (int pos)
  362. {
  363.     static char str2[256];
  364.     char suffix[16] = "";
  365.  
  366.     if (strstr (d_currLumpName, ".tga"))
  367.         sprintf (suffix, "%d%s", pos, ".tga");
  368.  
  369.     _makeTempFileName (str2, suffix);
  370.  
  371.     if (!pak_ExtractFile (d_pakFile, d_currLumpName, str2))
  372.     {
  373.         mxMessageBox (this, "Error extracting from PAK file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  374.         return 1;
  375.     }
  376.  
  377.     if (g_MDLViewer->getGlWindow ()->loadTexture (str2, pos))
  378.     {
  379.         if (pos == 0)
  380.             g_ControlPanel->setShowBackground (true);
  381.         else
  382.             g_ControlPanel->setShowGround (true);
  383.     }
  384.     else
  385.         mxMessageBox (this, "Error loading texture.",  g_appTitle, MX_MB_OK | MX_MB_ERROR);
  386.  
  387.     return 1;
  388. }
  389.  
  390.  
  391.  
  392. int
  393. PAKViewer::OnPlaySound ()
  394. {
  395. #ifdef WIN32
  396.     static char str2[256];
  397.     char suffix[16] = "";
  398.  
  399.     // stop any playing sound
  400.     PlaySound (0, 0, SND_FILENAME | SND_ASYNC);
  401.  
  402.     if (strstr (d_currLumpName, ".wav"))
  403.         sprintf (suffix, "%d%s", 44, ".wav");
  404.  
  405.     _makeTempFileName (str2, suffix);
  406.  
  407.     if (!pak_ExtractFile (d_pakFile, d_currLumpName, str2))
  408.     {
  409.         mxMessageBox (this, "Error extracting from PAK file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  410.         return 1;
  411.     }
  412.  
  413.     PlaySound (str2, 0, SND_FILENAME | SND_ASYNC);
  414.  
  415. #endif
  416.     return 1;
  417. }
  418.  
  419.  
  420.  
  421. int
  422. PAKViewer::OnExtract ()
  423. {
  424.     char *ptr = (char *) mxGetSaveFileName (this, "", "*.*");
  425.     if (ptr)
  426.     {
  427.         if (!pak_ExtractFile (d_pakFile, d_currLumpName, ptr))
  428.             mxMessageBox (this, "Error extracting from PAK file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  429.     }
  430.  
  431.     return 1;
  432. }
  433.  
  434.  
  435.  
  436. int
  437. _compare(const void *arg1, const void *arg2)
  438. {
  439.     if (strchr ((char *) arg1, '/') && !strchr ((char *) arg2, '/'))
  440.         return -1;
  441.  
  442.     else if (!strchr ((char *) arg1, '/') && strchr ((char *) arg2, '/'))
  443.         return 1;
  444.  
  445.     else
  446.         return strcmp ((char *) arg1, (char *) arg2);
  447. }
  448.  
  449.  
  450.  
  451. bool
  452. PAKViewer::openPAKFile (const char *pakFile)
  453. {
  454.     FILE *file = fopen (pakFile, "rb");
  455.     if (!file)
  456.         return false;
  457.  
  458.     int ident, dirofs, dirlen;
  459.  
  460.     // check for id
  461.     fread (&ident, sizeof (int), 1, file);
  462.     if (ident != (int) (('K' << 24) + ('C' << 16) + ('A' << 8) + 'P'))
  463.     {
  464.         fclose (file);
  465.         return false;
  466.     }
  467.  
  468.     // load lumps
  469.     fread (&dirofs, sizeof (int), 1, file);
  470.     fread (&dirlen, sizeof (int), 1, file);
  471.     int numLumps = dirlen / 64;
  472.  
  473.     fseek (file, dirofs, SEEK_SET);
  474.     lump_t *lumps = new lump_t[numLumps];
  475.     if (!lumps)
  476.     {
  477.         fclose (file);
  478.         return false;
  479.     }
  480.  
  481.     fread (lumps, sizeof (lump_t), numLumps, file);
  482.     fclose (file);
  483.  
  484.     qsort (lumps, numLumps, sizeof (lump_t), _compare);
  485.  
  486.     // save pakFile for later
  487.     strcpy (d_pakFile, pakFile);
  488.  
  489.     tvPAK->remove (0);
  490.  
  491.     char namestack[32][32];
  492.     mxTreeViewItem *tvistack[32];
  493.     for (int k = 0; k < 32; k++)
  494.     {
  495.         strcpy (namestack[k], "");
  496.         tvistack[k] = 0;
  497.     }
  498.  
  499.     for (int i = 0; i < numLumps; i++)
  500.     {
  501.         if (d_loadEntirePAK || !strncmp (lumps[i].name, "models", 6))
  502.         {
  503.             char *tok;
  504.             if (d_loadEntirePAK)
  505.                 tok = &lumps[i].name[0];
  506.             else
  507.                 tok = &lumps[i].name[7];
  508.  
  509.             int i = 1;
  510.             while (tok)
  511.             {
  512.                 char *end = strchr (tok, '/');
  513.                 if (end)
  514.                     *end = '\0';
  515.  
  516.                 if (strcmp (namestack[i], tok))
  517.                 {
  518.                     strcpy (namestack[i], tok);
  519. /*
  520.                     if (i == 0)
  521.                         tvistack[i] = tvPAK->add (0, tok);
  522.                     else*/
  523.                         tvistack[i] = tvPAK->add (tvistack[i - 1], tok);
  524.  
  525.                     for (int j = i + 1; j < 32; j++)
  526.                     {
  527.                         strcpy (namestack[j], "");
  528.                         tvistack[j] = 0;
  529.                     }
  530.                 }
  531.  
  532.                 ++i;
  533.  
  534.                 if (end)
  535.                     tok = end + 1;
  536.                 else
  537.                     tok = 0;
  538.             }
  539.         }
  540.     }
  541.  
  542.     delete[] lumps;
  543.  
  544.     setVisible (true);
  545.  
  546.     return true;
  547. }
  548.  
  549.  
  550.  
  551. void
  552. PAKViewer::closePAKFile ()
  553. {
  554.     strcpy (d_pakFile, "");
  555.     setVisible (false);
  556. }
  557.